﻿using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading;
using System.Linq;
using LucyGrid;
using System.Threading.Tasks;

namespace LucyGridTest
{
	/// <summary>
	/// Summary description for PerformanceTest
	/// </summary>
	[TestClass]
	public class PerformanceTest
	{
		TestHelper th;
		public PerformanceTest()
		{
			//
			// TODO: Add constructor logic here
			//
		}

		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
				th = new TestHelper(value);
			}
		}

		#region Additional test attributes
		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		// [ClassInitialize()]
		// public static void MyClassInitialize(TestContext testContext) { }
		//
		// Use ClassCleanup to run code after all tests in a class have run
		// [ClassCleanup()]
		// public static void MyClassCleanup() { }
		//
		// Use TestInitialize to run code before running each test 
		// [TestInitialize()]
		// public void MyTestInitialize() { }
		//
		// Use TestCleanup to run code after each test has run
		// [TestCleanup()]
		// public void MyTestCleanup() { }
		//
		#endregion
		[Serializable]
		public class TestInputData {
			public string StrData = new String('o', 2048);
			public int[] IntArrayData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		}

		public class TestOutData{
			public bool Ok = true;
		}

		public static TestOutData ProcessData(TestInputData data) {
			Thread.Sleep(1000);
			return new TestOutData();
		}

		/// <summary>
		/// Measures the time diff between running AsParallel and AsParallelGrid
		/// </summary>
		[TestMethod]
		public void Perf_AsParallelVsLocalAsParallelGrid()
		{
			// Some tweaks :)
			GridUtils.EnableLog = 0;
			
			var inpuData = Enumerable.Range(0, 60).Select(i => new TestInputData());
			long grid = 0;
			using (var nodes = th.StartGridNode(1))
			{
				var sw = System.Diagnostics.Stopwatch.StartNew();
				inpuData.AsParallelGrid(ProcessData).ToArray();
				sw.Stop();
				grid = sw.ElapsedMilliseconds;

			}
			GC.Collect();
			GC.WaitForPendingFinalizers();
			GC.Collect();
			Thread.Sleep(3000);

			var psw = System.Diagnostics.Stopwatch.StartNew();
			inpuData.AsParallel().Select(ProcessData).ToArray();
			var parallel = psw.ElapsedMilliseconds;

			GC.Collect();
			GC.WaitForPendingFinalizers();
			GC.Collect();
			Thread.Sleep(3000);


			var esw = System.Diagnostics.Stopwatch.StartNew();
			Task.WaitAll(Enumerable.Range(0, GridPerformance.NumberOfThreadsPerMachine)
			.Select(i => Task.Run(() =>
				{
					PerformanceTest.ProcessData(null);
				}))
			.ToArray());
			var localExecutor = esw.ElapsedMilliseconds; 
			

			System.Diagnostics.Debug.WriteLine(">>>>>>>>>>>>>   AsParallelGrid: " + grid);
			System.Diagnostics.Debug.WriteLine(">>>>>>>>>>>>>   AsParallel: " + parallel);
			System.Diagnostics.Debug.WriteLine(">>>>>>>>>>>>>   Local executor: " + localExecutor);
			System.Diagnostics.Debug.WriteLine(">>>>>>>>>>>>>   Grid overhead: " + (grid - parallel));
		}
	}
}
